package nachos.userprog;

import nachos.machine.*;
import nachos.threads.*;
import nachos.userprog.*;

import java.io.EOFException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;


/**
 *包装一个不包含用户线程的用户进程。这个包括了其地址转化状态，
 *一个文件表，和关于程序被执行的信息。
 *<p>
 *这个类可以被其他类继承以支持额外的功能（比如其他的系统调用等）
 * <p>
 * Encapsulates the state of a user process that is not contained in its
 * user thread (or threads). This includes its address translation state, a
 * file table, and information about the program being executed.
 * <p>
 * This class is extended by other classes to support additional functionality
 * (such as additional syscalls).
 *
 * @see	nachos.vm.VMProcess
 * @see	nachos.network.NetProcess
 */
public class UserProcess {
    /**
     * 构造方法。
     * Allocate a new process.
     */
    public UserProcess() {

	int numPhysPages = Machine.processor().getNumPhysPages();
//	numPhysPages =0;
//	System.out.println("hhh");
	pageTable = new TranslationEntry[numPhysPages];

	for (int i=0; i<numPhysPages; i++)
	    pageTable[i] = new TranslationEntry(i,i, true,false,false,false);
	  
	openFile = new OpenFile[maxOpenFile];
	openFile[0]=UserKernel.console.openForReading();
	openFile[1]=UserKernel.console.openForWriting();
	readCount = new int[maxOpenFile];
	writeCount = new int[maxOpenFile];
    }
    
    /**
     * 分配并且返回一个新的process，这个类名被nachos.conf中的Kernel.processClassName指定。
     * Allocate and return a new process of the correct class. The class name
     * is specified by the <tt>nachos.conf</tt> key
     * <tt>Kernel.processClassName</tt>.
     *
     * @return	a new process of the correct class.
     */
    public static UserProcess newUserProcess() {
	return (UserProcess)Lib.constructObject(Machine.getProcessClassName());
    }

    /**
     * 以特定参数执行特定程序。尝试载入程序，然后fork一个线程运行它。
     * Execute the specified program with the specified arguments. Attempts to
     * load the program, and then forks a thread to run it.
     *
     * @param	name	the name of the file containing the executable.
     * @param	args	the arguments to pass to the executable.
     * @return	<tt>true</tt> if the program was successfully executed.
     */
    public boolean execute(String name, String[] args) {
	if (!load(name, args))
	    return false;
    /***************************************/
    UserKernel.processAllocateLock.acquire();
    pid = UserKernel.getFreePid();
    if(pid==-1)
    {
    	Lib.debug(dbgProcess, "error");
    	return false;
    }
    UserKernel.processList[pid]=this;
    runningProcess++;
    Lib.debug(dbgProcess, "current Process :"+runningProcess);
    UserKernel.processAllocateLock.release();   
    /***************************************/
	new UThread(this).setName(name).fork();

	return true;
    }

    /**
     * 为了准备上下文切换，保存当前进程状态，由UThread.saveState调用。
     * <p>
     * Save the state of this process in preparation for a context switch.
     * Called by <tt>UThread.saveState()</tt>.
     */
    public void saveState() {
    }

    /**
     * 在上下文切换后恢复状态。由UThread.restoreState调用。
     * <p>
     * Restore the state of this process after a context switch. Called by
     * <tt>UThread.restoreState()</tt>.
     */
    public void restoreState() {
	Machine.processor().setPageTable(pageTable);
    }

    /**
     * 
     * 从进程的虚拟内存中读取了一个空终止字符串。从特定地址中读取最多maxLength+1个字节，
     * 搜索空终止字符，并且把它转化为一个{@link java.lang.String}对象，
     * 不包含最后一个空终止字符。如果没有找到空终止字符，返回null.
     * <p>
     * Read a null-terminated string from this process's virtual memory. Read
     * at most <tt>maxLength + 1</tt> bytes from the specified address, search
     * for the null terminator, and convert it to a <tt>java.lang.String</tt>,
     * without including the null terminator. If no null terminator is found,
     * returns <tt>null</tt>.
     *
     * @param	vaddr	the starting virtual address of the null-terminated
     *			string.
     * @param	maxLength	the maximum number of characters in the string,
     *				not including the null terminator.
     * @return	the string read, or <tt>null</tt> if no null terminator was
     *		found.
     */
    public String readVirtualMemoryString(int vaddr, int maxLength) {
	Lib.assertTrue(maxLength >= 0);
	//boolean isFirst = false;
	/****************************/
	holdLock.acquire();
	readLock.acquire();
	readThreadNumber++;
	if(readThreadNumber==1)
	{
		//isFirst = true;
		writeLock.acquire();
	}
	readLock.release();
	holdLock.release();
	/****************************/
	byte[] bytes = new byte[maxLength];

	int bytesRead = readVirtualMemory(vaddr, bytes);
	Lib.debug(dbgProcess, bytesRead+" bytesRead");
	//System.out.println();
	String res = null;
	for (int length=0; length<bytesRead; length++) {
	    if (bytes[length] == 0)
	    {
	    	res = new String(bytes, 0, length);
	    	break;
	    }
		//return new String(bytes, 0, length);
	}
	/****************************/
	readLock.acquire();
	readThreadNumber--;
	if(readThreadNumber==0)
	{
		writeLock.release();
	}
	readLock.release();
	/****************************/
	return res;
    }

    /**
     * Transfer data from this process's virtual memory to all of the specified
     * array. Same as <tt>readVirtualMemory(vaddr, data, 0, data.length)</tt>.
     *
     * @param	vaddr	the first byte of virtual memory to read.
     * @param	data	the array where the data will be stored.
     * @return	the number of bytes successfully transferred.
     */
    public int readVirtualMemory(int vaddr, byte[] data) {
	return readVirtualMemory(vaddr, data, 0, data.length);
    }

	/*
	 * 	String h = "hello";
	byte[] b=h.getBytes();
	int pos = -1;
	int len = b.length-1;
	boolean con=false;
	int count=0;
	System.out.println("checking");
	for(int i=0;i<b.length;i++)
	{
		System.out.print(b[i]+" ");
	}
	System.out.println();
	int im=0;
	for(int i=0;i<memory.length;i++)
	{
			if(memory[i]!=0)
			{
				//System.out.printf("%5d_%5d ",i,memory[i]);
				count++;
				im=i;
				if(count%20==0){
					System.out.println();
				}
			}
	}
	System.out.println(im);
	*/
	/*
	for(int i=0;i<memory.length;i++)
	{
		if(!con&&b[0]==memory[i])
		{
			con=true;
			pos=0;
			continue;
		}
		else if(con)
		{
			if(b[++pos]==memory[i])
			{
				if(pos==b.length-1){
					System.out.println(i+" success find");
					break;
				}
			}else
			{
				System.out.println("fail");
				con=false;
				pos=-1;
			}
		}
	}*/
	//System.out.println(memory[2048]);
	//System.out.println(memory[2049]);
    /**
     * Transfer data from this process's virtual memory to the specified array.
     * This method handles address translation details. This method must
     * <i>not</i> destroy the current process if an error occurs, but instead
     * should return the number of bytes successfully copied (or zero if no
     * data could be copied).
     *从虚拟的内存中拷贝指定的数组，这个方法处理地址转化的细节。
     *如果有错误发生，这个方法不能破坏当前进程，但是应该返回实际拷贝的字节数目（如果没有数据被拷贝，返回0）。
     * @param	vaddr	the first byte of virtual memory to read.虚拟内存的地址
     * @param	data	the array where the data will be stored.拷贝的数据存储的数组
     * @param	offset	the first byte to write in the array.写入数组的第一个字节的位置
     * @param	length	the number of bytes to transfer from virtual memory to
     *			the array.拷贝的字节的数目
     * @return	the number of bytes successfully transferred.
     */
    public int readVirtualMemory(int vaddr, byte[] data, int offset,
				 int length) {
	Lib.assertTrue(offset >= 0 && length >= 0 && offset+length <= data.length);

	byte[] memory = Machine.processor().getMemory();
	/***********************************************/
	int amount = 0;
	//虚拟页对应的实际物理页可能是间断的，所以要一部分一部分传
	//int read = 0;
	int total = length;
	int firstVpn = vaddr/pageSize;
	//int currentVpn=firstVpn;
	int totalVpn = (total+pageSize-1)/pageSize;
	int pageOffset =  vaddr%pageSize;
	for(int i=0;i<totalVpn;i++)
	{
		int currentVpn = firstVpn+i;
		int currentOffset=offset + amount;
		int currentAddress = pageTable[currentVpn].ppn*pageSize;
		if(currentVpn==firstVpn)currentAddress+=pageOffset;
		int currentAmount = 0;
		if(totalVpn==1)
		{
			currentAmount = total;
		}
		else if(i==0)
		{
			currentAmount = pageSize-pageOffset;
		}
		else if(i==totalVpn-1)
		{
			//减去第一页的部分然后取余
			currentAmount = (total+pageOffset)%pageSize;
		}
		else
		{
			currentAmount = pageSize;
		}
		amount +=currentAmount;
		System.arraycopy(memory, currentAddress, data, currentOffset,currentAmount );
	}
	return amount;
	/*
	int vpn = vaddr/pageSize;
	int voffset = vaddr%pageSize;
	int raddr = pageTable[vpn].ppn*pageSize+voffset;
	if (raddr < 0 || raddr >= memory.length)
	    return 0;

	int amount = Math.min(length, memory.length-raddr);
	System.arraycopy(memory, raddr, data, offset, amount);

	return amount;
		*/
	/***********************************************/
	// for now, just assume that virtual addresses equal physical addresses
	/*
	if (vaddr < 0 || vaddr >= memory.length)
	    return 0;
	
	int amount = Math.min(length, memory.length-vaddr);
	System.arraycopy(memory, vaddr, data, offset, amount);

	return amount;
	*/
    }
	
    /**
     * Transfer all data from the specified array to this process's virtual
     * memory.
     * Same as <tt>writeVirtualMemory(vaddr, data, 0, data.length)</tt>.
     *
     * @param	vaddr	the first byte of virtual memory to write.
     * @param	data	the array containing the data to transfer.
     * @return	the number of bytes successfully transferred.
     */
    public int writeVirtualMemory(int vaddr, byte[] data) {
	return writeVirtualMemory(vaddr, data, 0, data.length);
    }

    /**
     * Transfer data from the specified array to this process's virtual memory.
     * This method handles address translation details. This method must
     * <i>not</i> destroy the current process if an error occurs, but instead
     * should return the number of bytes successfully copied (or zero if no
     * data could be copied).
     *将特定数组中的数据写入内存。这个方法处理了地址转换的细节。
     *如果有错误发生，这个方法不应该破坏当前进程，应该返回成功写入的字节数。
     * @param	vaddr	the first byte of virtual memory to write.
     * @param	data	the array containing the data to transfer.
     * @param	offset	the first byte to transfer from the array.
     * @param	length	the number of bytes to transfer from the array to
     *			virtual memory.
     * @return	the number of bytes successfully transferred.
     */
    public int writeVirtualMemory(int vaddr, byte[] data, int offset,
				  int length) {
    	holdLock.acquire();
    writeLock.acquire();
    try
    	{
    	Lib.assertTrue(offset >= 0 && length >= 0 && offset+length <= data.length);

    	length = (vaddr+length)>numPages*pageSize?numPages*pageSize-vaddr:length;
    	
    	byte[] memory = Machine.processor().getMemory();
	
    	/****************************/
    	int amount = 0;
    	int total = length;
    	int firstVpn = vaddr/pageSize;
    	int pageOffset = vaddr%pageSize;
    	int totalVpn = (length+pageSize-1)/pageSize;
    	for(int i=0;i<totalVpn;i++)
    	{
    		int currentVpn=firstVpn+i;
    		int currentOffset=offset+amount;
    		int currentAddress = pageTable[currentVpn].ppn*pageSize;
    		if(currentVpn==firstVpn)currentAddress += pageOffset;
    		int currentAmount = 0;
    		if(totalVpn==1)
    		{
    			currentAmount = total;
    		}
    		else if(i==0)
    		{
    			currentAmount = pageSize-pageOffset;
    		}
    		else if(i==totalVpn-1)
    		{
    			//减去第一页的部分然后取余
    			currentAmount = (total+pageOffset)%pageSize;
    		}
    		else
    		{
    			currentAmount = pageSize;
    		}
    		amount +=currentAmount;
    		System.arraycopy(data, currentOffset, memory, currentAddress,currentAmount);
    	}
    	
    	return amount;
    	/*
    	int vpn = vaddr/pageSize;
    	int voffset = vaddr%pageSize;
    	int raddr = pageTable[vpn].ppn+voffset;
    	if (raddr < 0 || raddr >= memory.length)
    		return 0;

    	int amount = Math.min(length, memory.length-raddr);
    	System.arraycopy(data, offset, memory, raddr, amount);
    
    	return amount;
    	
    	*/
    	/****************************/
	// for now, just assume that virtual addresses equal physical addresses
    	/*
    	if (vaddr < 0 || vaddr >= memory.length)
    		return 0;

    	int amount = Math.min(length, memory.length-vaddr);
    	System.arraycopy(data, offset, memory, vaddr, amount);
    
    	return amount;
    	*/
    	}finally
    	{
    		writeLock.release();
    		holdLock.release();
    	}
    }

    /**
     *载入特定名称的可执行文件，并且准备通过特定参数（？）。
     *<p>打开可执行文件，读取头信息，并且拷贝各部分和参数到内存中。
     *<p>
     * 此处包含了一个将参数写入内存的方法：
     * <ol>
     * <li>将String[] args转成byte[][] argv，并统计argv中byte数目（argsSize）
     * <li>确定存入参数的页号(numPages-1)，并进而确定地址(entryOffset)
     * <li>将页的头args.length*4个字节存入参数的起始地址（stringOffset），每4个字节是一个地址，代表字符串的位置
     * <li>将对应的字符串存入对应的地址，并且以0结尾
     * </ol>
     * Load the executable with the specified name into this process, and
     * prepare to pass it the specified arguments. Opens the executable, reads
     * its header information, and copies sections and arguments into this
     * process's virtual memory.
 
     * @param	name	the name of the file containing the executable.
     * @param	args	the arguments to pass to the executable.
     * @return	<tt>true</tt> if the executable was successfully loaded.
     */
    private boolean load(String name, String[] args) {
	Lib.debug(dbgProcess, "UserProcess.load(\"" + name + "\")");
	/**
	 * 打开该文件
	 * */
	OpenFile executable = ThreadedKernel.fileSystem.open(name, false);
	if (executable == null) {
	    Lib.debug(dbgProcess, "\topen failed");
	    //System.out.println(1);
	    return false;
	}
/**
 * 将文件包装为可执行文件
 * */
	try {
	    coff = new Coff(executable);
	}
	catch (EOFException e) {
	    executable.close();
	    Lib.debug(dbgProcess, "\tcoff load failed");
	    return false;
	}
/**
 * 统计程序中页的数目（根据每段中页的数目来确定）
 * */
	// make sure the sections are contiguous and start at page 0
	numPages = 0;
	for (int s=0; s<coff.getNumSections(); s++) {
	    CoffSection section = coff.getSection(s);
	    if (section.getFirstVPN() != numPages) {
		coff.close();
		Lib.debug(dbgProcess, "\tfragmented executable");
		return false;
	    }
	    numPages += section.getLength();
	}
/**
 * 确保argv占据一页<p>
 * */
	// make sure the argv array will fit in one page
	byte[][] argv = new byte[args.length][];
	int argsSize = 0;
	for (int i=0; i<args.length; i++) {
	    argv[i] = args[i].getBytes();
	    
	    // 4 bytes for argv[] pointer; then string plus one for null byte
	    argsSize += 4 + argv[i].length + 1;
	}
	if (argsSize > pageSize) {
	    coff.close();
	    Lib.debug(dbgProcess, "\targuments too long");
	    return false;
	}

	//将程序的进入点赋值PC  program counter initially points at the program entry point
	initialPC = coff.getEntryPoint();	

	//栈指针位于栈顶 next comes the stack; stack pointer initially points to top of it
	numPages += stackPages;
	initialSP = numPages*pageSize;

	//最后留一页给参数  and finally reserve 1 page for arguments
	numPages++;


	if (!loadSections())
	    return false;

	// 在最后一页中存入参数 store arguments in last page
	int entryOffset = (numPages-1)*pageSize;
	int stringOffset = entryOffset + args.length*4;

	this.argc = args.length;
	this.argv = entryOffset;
	
	for (int i=0; i<argv.length; i++) {
	    byte[] stringOffsetBytes = Lib.bytesFromInt(stringOffset);
	    Lib.assertTrue(writeVirtualMemory(entryOffset,stringOffsetBytes) == 4);
	    entryOffset += 4;
	    Lib.assertTrue(writeVirtualMemory(stringOffset, argv[i]) ==
		       argv[i].length);
	    stringOffset += argv[i].length;
	    Lib.assertTrue(writeVirtualMemory(stringOffset,new byte[] { 0 }) == 1);
	    stringOffset += 1;
	}
	this.name = name;
	return true;
    }

    /**
     * Allocates memory for this process, and loads the COFF sections into
     * memory. If this returns successfully, the process will definitely be
     * run (this is the last step in process initialization that can fail).
     *为进程分配内存，并且把代码段(coff section)载入内存。如果成功返回，
     *进程会开始执行（这是进程初始化过程中最后一个可能会失败的阶段）。
     * @return	<tt>true</tt> if the sections were successfully loaded.
     */
    protected boolean loadSections() {
    /*	
	if (numPages > Machine.processor().getNumPhysPages()) {
	    coff.close();
	    Lib.debug(dbgProcess, "\tinsufficient physical memory");
	    return false;
	}*/
	/****************************/
    	UserKernel.sectionLock.acquire();
    if (numPages > UserKernel.freePageList.size()) {
    	   coff.close();
    	   Lib.debug(dbgProcess, "\tinsufficient physical memory");
    	   UserKernel.sectionLock.release();
    	   return false;
    }
	pageTable = new TranslationEntry[numPages];

	for(int i=0;i<numPages;i++)
	{
		int page = UserKernel.freePageList.remove();
		pageTable[i] =new TranslationEntry(i,page, true,false,false,false);
	}
	UserKernel.sectionLock.release();
	/****************************/
	
	// load sections
	for (int s=0; s<coff.getNumSections(); s++) {
	    CoffSection section = coff.getSection(s);
	    
	    Lib.debug(dbgProcess, "\tinitializing " + section.getName()
		      + " section (" + section.getLength() + " pages)");

	    
	    for (int i=0; i<section.getLength(); i++) {
		int vpn = section.getFirstVPN()+i;
		/***********************************/
		pageTable[vpn].readOnly=section.isReadOnly();
		section.loadPage(i,pageTable[vpn].ppn);
		/***********************************/
		// for now, just assume virtual addresses=physical addresses
		//section.loadPage(i, vpn);
	    }
	}
	
	return true;
    }

    /**
     * Release any resources allocated by <tt>loadSections()</tt>.
     */
    protected void unloadSections() {
    }    

    /**
     * 为了准备运行程序，初始化CPU寄存器。设置PC寄存器的值为函数开头，
     * 设置栈指针为栈顶，设置A0和A1寄存器的值为argc和argv，
     * 分别地，设置其他寄存器初值为0
     * <p>
     * Initialize the processor's registers in preparation for running the
     * program loaded into this process. Set the PC register to point at the
     * start function, set the stack pointer register to point at the top of
     * the stack, set the A0 and A1 registers to argc and argv, respectively,
     * and initialize all other registers to 0.
     */
    public void initRegisters() {
	Processor processor = Machine.processor();

	// by default, everything's 0
	for (int i=0; i<processor.numUserRegisters; i++)
	    processor.writeRegister(i, 0);

	// initialize PC and SP according
	processor.writeRegister(Processor.regPC, initialPC);
	processor.writeRegister(Processor.regSP, initialSP);

	// initialize the first two argument registers to argc and argv
	processor.writeRegister(Processor.regA0, argc);
	processor.writeRegister(Processor.regA1, argv);
    }

    /**
     * Handle the halt() system call. 
     * 处理系统调用——halt()
     */
    private int handleHalt() {
    /******************************/
    if(this.pid!=0)
    {
    	return 0;
    }
    /*****************************/
	Machine.halt();
	
	Lib.assertNotReached("Machine.halt() did not halt machine!");
	return 0;
    }


    private static final int
        syscallHalt = 0,
	syscallExit = 1,
	syscallExec = 2,
	syscallJoin = 3,
	syscallCreate = 4,
	syscallOpen = 5,
	syscallRead = 6,
	syscallWrite = 7,
	syscallClose = 8,
	syscallUnlink = 9;

    /**
     * 处理系统调用异常。由{@link UserProcess#handleException(int)}调用。
     * 系统调用的参数标识了用户会执行哪一个系统调用：
     * Handle a syscall exception. Called by <tt>handleException()</tt>. The
     * <i>syscall</i> argument identifies which syscall the user executed:
     *
     * <table>
     * <tr><td>syscall#</td><td>syscall prototype</td></tr>
     * <tr><td>0</td><td><tt>void halt();</tt></td></tr>
     * <tr><td>1</td><td><tt>void exit(int status);</tt></td></tr>
     * <tr><td>2</td><td><tt>int  exec(char *name, int argc, char **argv);
     * 								</tt></td></tr>
     * <tr><td>3</td><td><tt>int  join(int pid, int *status);</tt></td></tr>
     * <tr><td>4</td><td><tt>int  creat(char *name);</tt></td></tr>
     * <tr><td>5</td><td><tt>int  open(char *name);</tt></td></tr>
     * <tr><td>6</td><td><tt>int  read(int fd, char *buffer, int size);
     *								</tt></td></tr>
     * <tr><td>7</td><td><tt>int  write(int fd, char *buffer, int size);
     *								</tt></td></tr>
     * <tr><td>8</td><td><tt>int  close(int fd);</tt></td></tr>
     * <tr><td>9</td><td><tt>int  unlink(char *name);</tt></td></tr>
     * </table>
     * 
     * @param	syscall	the syscall number.
     * @param	a0	the first syscall argument.
     * @param	a1	the second syscall argument.
     * @param	a2	the third syscall argument.
     * @param	a3	the fourth syscall argument.
     * @return	the value to be returned to the user.
     */
    public int handleSyscall(int syscall, int a0, int a1, int a2, int a3) {
	switch (syscall) {
	case syscallHalt:
	    return handleHalt();
	    /***********************************/
	case syscallJoin:
		return handleJoin(a0, a1);
	case syscallExec:
		return handleExec(a0,a1,a2);
	case syscallExit:
		return handleExit(a0);
	case syscallCreate:
		return handleFileCreate(a0);
	case syscallOpen:
		return handleFileOpen(a0);
	case syscallRead:
		return handleFileRead(a0, a1, a2);
	case syscallWrite:
		return handleFileWrite(a0,a1,a2);
	case syscallClose:
	//	Lib.debug('a', a0+" a0");
	//	Lib.debug('a', a1+" a1");
	//	Lib.debug('a', a2+" a2");
	//	Lib.debug('a', a3+" a3");
		return handleFileClose(a0);
	case syscallUnlink:
		return handleFileUnlink(a0);
	    /***********************************/
	default:
	    Lib.debug(dbgProcess, "Unknown syscall " + syscall);
	    Lib.assertNotReached("Unknown system call!"+syscall);
	}
	return 0;
    }
    /******************************************/
    public int handleJoin(int pid,int statusAddress)
    {
    	joinLock.acquire();
    	joinCondition.sleep();
    	joinLock.release();
    	int status = UserKernel.processStatus[pid];
    	byte[] data = Lib.bytesFromInt(status);
    	int num = writeVirtualMemory(statusAddress, data);
    	Lib.assertTrue(num==4);
    	if(status==0)return 1;
    	return 0;
    }
    public int  handleExec(int fileAddress,int addressCount,int argvAddress)
    {
    	String filename = readVirtualMemoryString(fileAddress, 256);
    	int argc = addressCount;
    	int entryOffset = argvAddress;
    	String[] args = new String[argc];
    	byte[] stringOffsetByte = new byte[4];
    	for(int i=0;i<argc;i++)
    	{
    		readVirtualMemory(entryOffset, stringOffsetByte);
    		int stringOffset = Lib.bytesToInt(stringOffsetByte,0);
    		args[i]=readVirtualMemoryString(stringOffset, 256);
    		entryOffset +=4;
    	}
    	UserProcess process = UserProcess.newUserProcess();
    	boolean flag = process.execute(filename, args);
    	if(!flag)return -1;
    	process.ppid=pid;
    	if(pid!=0)this.children.add(process.pid);
    	return process.getPid();
    }
    public int handleExit(int args)
    {
    	coff.close();
    	Lib.debug(dbgProcess, "coff close");
    	//恢复页表
    	//lock
    	byte[] memory = Machine.processor().getMemory();
    	UserKernel.sectionLock.acquire();
    	this.unloadSections();
    	for(int i=0;i<pageTable.length;i++)
    	{
    		int ppn = pageTable[i].ppn;
    		pageTable[i].valid=false;
    		int addr = ppn*pageSize;
    		Arrays.fill(memory, addr, addr+pageSize, (byte)0);
    		UserKernel.freePageList.add(ppn);
    	}
    	UserKernel.sectionLock.release();
    	Lib.debug(dbgProcess, "page clear");
    	//关闭打开的文件
    	for(int i=0;i<openFile.length;i++)
    	{
    		OpenFile f = openFile[i];
    		if(f!=null){
    			f.close();
    			openFile[i]=null;
    		}
    	}	
    	Lib.debug(dbgProcess, "fd close");
    
    	//将该进程管理的子进程退出
    	int[] chd = new int[children.size()];
    	Iterator<Integer> it = children.iterator();
    	int i=0;
    	while(it.hasNext())
    	{
    		chd[i++]=it.next();
    	}
    	for(int c:chd)
    	{
    		UserProcess proc = UserKernel.processList[c];
    		proc.handleExit(0);
    	}
    	Lib.debug(dbgProcess, "remove children ");
    	
    	
    	//将子进程从父进程中移除
    	UserKernel.processAllocateLock.acquire();
    	UserKernel.processList[pid]=null;
        runningProcess--;
    	UserProcess parent = UserKernel.processList[ppid];
    	if(parent!=null&&ppid!=pid)
    	{
    		boolean b = parent.children.remove((Integer)pid);
    		if(b){};
    	}
    	UserKernel.processAllocateLock.release();
    	Lib.debug(dbgProcess, "process remove from parent");
    	Lib.debug(dbgProcess, "currentRunning process "+runningProcess);
    	
    	UserKernel.processStatus[pid]=args;
    	if(parent!=null&&ppid!=pid)
    	{	parent.joinLock.acquire();
    		parent.joinCondition.wake();
    		parent.joinLock.release();
    	}
    	if(runningProcess==0)
    	{
    		if(pid==0)
    		{
    			Machine.halt();
    		}
    		else
    		{
    			Kernel.kernel.terminate();
    		}
    	}
    	else
    	{
        	KThread.finish();
    	}
    	return args;
    }
    public int handleFileCreate(int a0)
    {
    	Lib.debug(dbgProcess, "handler syscall file create ");
    	String filename = readVirtualMemoryString(a0,  256);
    	if(filename==null||filename.length()==0){
    		Lib.debug(dbgProcess, "filename is too short");
    		return -1;
    	}
    	else
    	{
    		Lib.debug(dbgProcess, "filename length is "+filename.length());
    	}
    	Lib.debug(dbgProcess, "filename "+filename);
    //	Lib.debug(dbgProcess, "filename2 " +  readVirtualMemoryString(a1,  256));
    	OpenFile file = ThreadedKernel.fileSystem.open(filename, true);
    	int fd = getEmptyDescriber();
    	if(fd>=0)openFile[fd]=file;
    	return fd;
    }
    public int handleFileOpen(int a0)
    {
    	Lib.debug(dbgProcess, "handler syscall file open ");
    	String filename = readVirtualMemoryString(a0,  256);
    	Lib.debug(dbgProcess, filename);
    	if(filename!=null&&filename.equals(UserKernel.processFile))
    	{
    		UserKernel.updateProcessFile();
    	}
    	OpenFile file = ThreadedKernel.fileSystem.open(filename, false);
    	int fd = getEmptyDescriber();
    	if(fd>=0)openFile[fd]=file;
    	return fd;
    }
    public int handleFileRead(int fd,int buffer_point,int length)
    {
    //	Lib.debug(dbgProcess, "handler syscall file read fd is "+fd);
    	//byte[] buffer = r
    	if(fd<0||openFile[fd]==null)return -1;
    	OpenFile file = openFile[fd];
    	byte[] buf = new byte[length];
    //int c = file.read(readCount[fd], buf, 0, length);
    	int c = file.read(buf, 0, length);
    	/*
    	for(int i=0;i<buf.length;i++)
    	{
    		System.out.print(buf[i]+" ");
    	}*/
    	readCount[fd]+=c;
    	writeVirtualMemory(buffer_point, buf);
    	return c;
    }
    public int handleFileWrite(int fd,int buffer_point,int length)
    {
    	Lib.debug(dbgProcess, "handler syscall file write ");
    	if(fd<0||openFile[fd]==null)return -1;
    	OpenFile file = openFile[fd];
    	byte[] buf = new byte[length];
    	readVirtualMemory(buffer_point, buf);
    	//int c = file.write(writeCount[fd], buf, 0, length);
    	int c = file.write(buf, 0, length);
    	writeCount[fd]+=c;
    	return c;
    }
    public int handleFileUnlink(int fileAddress)
    {
    	String filename = readVirtualMemoryString(fileAddress,256);
    	if(filename==null)
    		return -1;
    	if(ThreadedKernel.fileSystem.remove(filename))
    	{
    		return 0;
    	}else
    	{
    		return -1;
    		}
    }
    public int handleFileClose(int fd)
    {
    	Lib.debug(dbgProcess, "handler syscall file close ");
    	if(fd<0||openFile[fd]==null)return -1;
    	OpenFile file = openFile[fd];
    	file.close();
    	openFile[fd]=null;
    	writeCount[fd]=0;
    	readCount[fd]=0;
    	return 0;
    }
    public int getEmptyDescriber()
    {
    	int i=0;
    	for(i=0;i<maxOpenFile;i++)
    	{
    		if(openFile[i]==null){
    			readCount[i]=0;
    			writeCount[i]=0;
    			return i;
    		}
    	}
    	return -1;
    }
    /******************************************/
    /**
     * 处理用户异常。由UserKernel.exceptionHandler()调用。
     * cause参数决定了哪一个异常会被调用；而这些参数可以参照{@link Processor}类的exception***常量。
     * <p>
     * Handle a user exception. Called by
     * <tt>UserKernel.exceptionHandler()</tt>. The
     * <i>cause</i> argument identifies which exception occurred; see the
     * <tt>Processor.exceptionZZZ</tt> constants.
     *
     * @param	cause	the user exception that occurred.
     */
    public void handleException(int cause) {
	Processor processor = Machine.processor();

	switch (cause) {
	case Processor.exceptionSyscall:
	    int result = handleSyscall(processor.readRegister(Processor.regV0),
				       processor.readRegister(Processor.regA0),
				       processor.readRegister(Processor.regA1),
				       processor.readRegister(Processor.regA2),
				       processor.readRegister(Processor.regA3)
				       );
	    processor.writeRegister(Processor.regV0, result);
	    processor.advancePC();
	    break;				       
				       
	default:
	    Lib.debug(dbgProcess, "Unexpected exception: " +
		      Processor.exceptionNames[cause]);
	    Lib.assertNotReached("Unexpected exception");
	}
    }

    /**由该进程运行的程序。 The program being run by this process. */
    protected Coff coff;

    /**进程的页表。 This process's page table. */
    protected TranslationEntry[] pageTable;
    /** 由程序所占用的连续的页的数目。The number of contiguous pages occupied by the program. */
    protected int numPages;

    /**程序栈中的页的数目。 The number of pages in the program's stack. */
    protected final int stackPages = 8;
    
    private int initialPC, initialSP;
    private int argc, argv;
	
    private static final int pageSize = Processor.pageSize;
    private static final char dbgProcess = 'a';
    
    /*********************/
    private OpenFile[] openFile;
    private int[] readCount;
    private int[] writeCount;
    private int maxOpenFile=16;
   // private int openCount=0;
   // private Lock writeLock = new Lock();
    
    private int readThreadNumber = 0;
    private int WriteNumber = 0;
    private Lock readLock=new Lock();
    private Lock writeLock = new Lock();
    private Lock holdLock = new Lock();
    private Lock joinLock = new Lock();
    private Condition joinCondition = new Condition(joinLock);
    private LinkedList<Integer> children = new LinkedList<Integer>();
    private static int runningProcess = 0;
    private int pid = -1;
    public  int ppid=0;
    public int getPid()
    {
    	return pid;
    }
    public int getPPid()
    {
    	return ppid;
    }
    public String name = null;
    /*********************/
}
